//下面这三个类，对于真正的OOP语言来说，说是接口更恰当一点

/*
方法链式支持，链上的方法会依次执行，而不是同时执行，通常用于Fx及其派生类中
需要对目标类使用显示使用Imeplements实现，然后在相关位置调用callChain
*/
var Chain = new Class({

 //对Implement Chain的对象，可以直接使用chain方法添加后续方法，主要是对外的接口
 chain: function(){
  this.$chain = (this.$chain || []).extend(arguments);
  return this;
 },

 //Implement对象本身的内部方法，使链式执行得以实现
 callChain: function(){
  return (this.$chain && this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
 },

 //清空链上所有等执行的方法
 clearChain: function(){
  if (this.$chain) this.$chain.empty();
  return this;
 }

});

/*
类事件支持
对于自封装UI组件，它非常有用，而且是必需的，远比UWA的callback优雅得多
*/
var Events = new Class({

 //添加单个事件
 addEvent: function(type, fn, internal){

  //因为在options中使用onEventName : $empty，所以有此判断
  if (fn != $empty){
   //使用||赋默认值
   this.$events = this.$events || {};
   //使用||赋默认值
   this.$events[type] = this.$events[type] || [];
   //数组的include方法
   this.$events[type].include(fn);
   //是否内置事件
   if (internal) fn.internal = true;
  }
  return this;
 },

 //添加多个事件
 addEvents: function(events){
  for (var type in events) this.addEvent(type, events[type]);
  return this;
 },

 //触发事件
 fireEvent: function(type, args, delay){
  if (!this.$events || !this.$events[type]) return this;
  //数组的遍历，通知每个订阅对象
  this.$events[type].each(function(fn){
   fn.create({'bind': this, 'delay': delay, 'arguments': args})();
  }, this);
  return this;
 },

 //移除单个事件
 removeEvent: function(type, fn){
  //如果私有变量无值，表明不存在事件订阅，因此不需要处理
  if (!this.$events || !this.$events[type]) return this;

  //非内置事件才擦除
  if (!fn.internal) this.$events[type].erase(fn);
  return this;
 },

 //移除某个事件的所有订阅通知
 removeEvents: function(type){
  for (var e in this.$events){
   if (type && type != e) continue;
   var fns = this.$events[e];
   for (var i = fns.length; i--; i) this.removeEvent(e, fns[i]);
  }
  return this;
 }

});

/*
构造函数可选参数支持，
需要对目标类使用显示使用Imeplements实现，然后在相关位置调用setOptions(通常在初始化的函数中)
*/
var ōptions = new Class({

 /*
 将传入的参数与this.options中的默认参数合并
 其中以on打头紧跟一大写字母的参数，并且值为函数类型，将作为事件处理
 */
 setOptions: function(){

  //注意函数的run方法和数组的extend方法
  this.options = $merge.run([this.options].extend(arguments));

  /*
  如果Implement了Events对象，会自动产生addEvent方法
  换言之，不具有addEvent方法的话，接下来的处理事件的代码便没了意义，因此返回
  */
  if (!this.addEvent) return this;
  for (var option in this.options){

   //仅当属性名on打头紧跟一大写字母的参数，并且值为函数类型，才作为事件处理
   if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;

   //添加事件
   this.addEvent(option, this.options[option]);

   //清除属性
   delete this.options[option];
  }
  return this;
 }

});